package com.cis.fingerprint.core;

import com.cis.fingerprint.utils.ByteUtils;
import com.fazecast.jSerialComm.SerialPort;
import com.sun.deploy.ui.AboutDialog;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * 发送指令操作管理
 */
@Component
public class SendAndReceiveDataManager {

    @Autowired
    WebSocketManager webSocketManager;

    /**
     * 发送、验证密码
     *
     * @param port 设备
     * @param bPID 指令码
     * @return 结果
     */
    public boolean sendPassword(SerialPort port, byte bPID) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand = new byte[]{CodeManager.B_COMMAND_VFY_PWD, 0x00, 0x00, 0x00, 0x00}; //命令包
        byte[] barrPackage = PackageManager.constructPackageData(bPID, barrCommand);  //通讯包
        receivedData = getBytes(port, barrPackage);
        int answerCode = PackageManager.analyzePackageReceived(receivedData);
        return (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 获取指纹图像
     */
    public boolean getImage(SerialPort port, byte bPID) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode = -1; //应答码
        barrCommand = new byte[]{CodeManager.B_COMMAND_GETIMG};
        //构建GetImage通讯包
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        //发送通讯包
        receivedData = getBytes(port, barrPackage);
        //解析GetImage通讯包
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        return (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 创建图像特征，并存储到特征缓冲区
     *
     * @param i 特征缓冲区号，可用值1~5
     */
    public boolean genChar(SerialPort port, byte bPID, int i) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode = -1; //应答码
        //构建GenChar通讯包
        //ByteUtils.hexStr2Byte(ByteUtils.byteToHex((byte) (i+1)))[0] -> 0x01, 0x02(特征缓冲区序号)
        barrCommand = new byte[]{CodeManager.B_COMMAND_GENCHAR, ByteUtils.hexStr2Byte(ByteUtils.byteToHex((byte) (i+1)))[0]};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        //发送通讯包
        receivedData = getBytes(port, barrPackage);
        //解析GenChar通讯包
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        return (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 将特征缓冲区1~2中的特征生成模板并存到特征缓冲区1中
     */
    public boolean regModel(SerialPort port, byte bPID) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode = -1; //应答码
        //构建RegModel通讯包
        barrCommand = new byte[]{CodeManager.B_COMMAND_REG_MODEL};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
        //解析GenChar通讯包
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        return (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 将特征缓冲区的特征模板存储到FLASH数据库中
     */
    public boolean storeModel(SerialPort port, byte bPID, int flashId){
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode = -1; //应答码
        //注册序号
        byte[] tempId = ByteUtils.intToTowByteArray(flashId);
        //构建StoreModel通讯包
        barrCommand = new byte[]{CodeManager.B_COMMAND_STORE_MODEL, 0x01};
        barrCommand = ArrayUtils.addAll(barrCommand, tempId);
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
//        解析GenChar通讯包
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        return (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 将指纹特征缓冲区的特征上传给上位机
     */
    public boolean upChar(SerialPort port, byte bPID) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode = -1; //应答码
        //构建UpChar通讯包
        //0x01特征缓冲区编号
        barrCommand = new byte[]{CodeManager.B_COMMAND_UP_CHAR, 0x01};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
        //解析UpChar通讯包
        answerCode = PackageManager.analyzePackageReceived(receivedData);

//        if (answerCode == CodeManager.B_ACK_RET_OK){
//            //通讯包正确，随后接收数据包
//            receivedData = getBytes(port, barrPackage);
//
//        }
        return (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 获取图像
     */
    public byte[] upImage(SerialPort port,  byte bPID) throws InterruptedException {
        byte[] receivedData;   //接收字节
        byte[] barrDataReceived = null;  //接收数据包
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode = -1; //应答码
        //构建getImage通讯包
        barrCommand = new byte[]{CodeManager.B_COMMAND_UP_IMAGE};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        if (answerCode == CodeManager.B_ACK_RET_OK){
            barrDataReceived  = getDataPackages(port);
        }
        return barrDataReceived;
    }

    /**
     *获取当前FLASH中的有效模板
     */
    public int getTemplateNum (SerialPort port, byte bPID) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode; //应答码
        int templateNum = 100; //当前模板数量
        //构建getTemplateNum通讯包
        barrCommand = new byte[]{CodeManager.B_COMMAND_TEMPLATE_NUM};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
        //解析构建getTemplateNum通讯包
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        if (answerCode == CodeManager.B_ACK_RET_OK){
            //获取数据
            templateNum = ByteUtils.towByteArrayToInt(
                    ArrayUtils.subarray(
                            receivedData,
            (int) CodeManager.B_ACK_RET_TYPE_PST + 1,
            receivedData.length - 2)
            );
        }
        return templateNum;
    }

    /**
     * 删除指纹模板
     */
    public boolean deleteChar(SerialPort port, byte bPID, Integer flashId) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode; //应答码
        //构建searchModel通讯包
        byte[] modelNumBytes = ByteUtils.intToTowByteArray(flashId);
        byte[] deleteNumBytes = ByteUtils.intToTowByteArray(1);
        barrCommand = new byte[]{CodeManager.B_COMMAND_DELETE_CHAR, modelNumBytes[0], modelNumBytes[1],deleteNumBytes[0], deleteNumBytes[1]};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        return  (answerCode == CodeManager.B_ACK_RET_OK);
    }

    /**
     * 验证指纹
     */
    public int searchModel(SerialPort port, byte bPID, int modelNum) {
        byte[] receivedData;   //接收字节
        byte[] barrCommand;  //命令包
        byte[] barrPackage;  //通讯包
        int answerCode; //应答码
        //构建searchModel通讯包
        byte[] modelNumBytes = ByteUtils.intToTowByteArray(modelNum);
        barrCommand = new byte[]{CodeManager.B_COMMAND_SEARCH, 0x01, 0x00, 0x00, modelNumBytes[0], modelNumBytes[1]};
        barrPackage = PackageManager.constructPackageData(bPID, barrCommand);
        receivedData = getBytes(port, barrPackage);
        answerCode = PackageManager.analyzePackageReceived(receivedData);
        if (answerCode == CodeManager.B_ACK_RET_OK){
            modelNum = ByteUtils.towByteArrayToInt(ArrayUtils.subarray(receivedData, (CodeManager.B_ACK_RET_TYPE_PST + 1), (CodeManager.B_ACK_RET_TYPE_PST + 3)));
            return modelNum;
        }
        return -1;
    }

    /**
     * 接收数据包
     * @param port 设备串口
     * @return 数据包
     */
    private byte[] getDataPackages(SerialPort port) {
        byte[] barrDataPackageReceived = null;
        byte[] data = null;
        //读取部分数据包，解析数据包大小
        byte[] barrPackagePreContentReceive = new byte[CodeManager.B_ACK_RET_PACKAGE_PRE_CONTENT_SIZE];
        byte bPIDReceived = 0;
        int answerCode = 0;
        int nDataHasRead = 0;
        try {
            while (bPIDReceived != CodeManager.B_PID_LAST_DATA) {
                while (port.bytesAvailable() == 0) {
                    Thread.sleep(20);
                }
                port.readBytes(barrPackagePreContentReceive, barrPackagePreContentReceive.length);
                int nSizeOfNextContent = PackageManager.getTheSizeOfNextContent(barrPackagePreContentReceive);
                byte[] barrContent = new byte[nSizeOfNextContent];
                while (port.bytesAvailable() < nSizeOfNextContent) {
                    Thread.sleep(20);
                }
                port.readBytes(barrContent, barrContent.length);
                barrDataPackageReceived = ArrayUtils.addAll(barrPackagePreContentReceive, barrContent);
                if (data == null) {
                    data = barrDataPackageReceived;
                } else {
                    byte[] temp = new byte[barrDataPackageReceived.length];
                    data = ArrayUtils.addAll(data, temp);
                }
                answerCode = PackageManager.analyzePackageReceived(barrDataPackageReceived);
                if (answerCode == CodeManager.B_ACK_RET_OK) {
                    bPIDReceived = barrDataPackageReceived[CodeManager.B_ACK_RET_PID_PST];
                    System.arraycopy(
                            barrDataPackageReceived,
                            CodeManager.B_ACK_RET_PACKAGE_PRE_CONTENT_SIZE,
                            data,
                            nDataHasRead,
                            nSizeOfNextContent - 2
                    );
                    nDataHasRead += (nSizeOfNextContent - 2);
                }
            }
            return ArrayUtils.subarray(data, 0, nDataHasRead);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 发送并接收字节流
     * @param port 设备
     * @param barrPackage 通讯包
     * @return 结构字节
     */
    private byte[] getBytes(SerialPort port, byte[] barrPackage) {
        byte[] receivedData = new byte[]{};
        int numRead = 0;
        port.writeBytes(barrPackage, barrPackage.length);
        try {
            while (numRead < 12){
                while (port.bytesAvailable() == 0)
                    Thread.sleep(20);
                receivedData = new byte[port.bytesAvailable()];
                numRead = port.readBytes(receivedData, receivedData.length);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return receivedData;
    }


}


